#include "stereo_binary_feature.h"


namespace ghicp
{

boost::shared_array<unsigned char> StereoBinaryFeature::make_shared()
{
	boost::shared_array<unsigned char> result(new unsigned char[byte_]);
	for (int i = 0; i < byte_; i++)
		result[i] = feature_[i];
	return result;
}

//How many 1 in a binary  number converted from a Hexadecimal
unsigned char StereoBinaryFeature::byteBitsLookUp(unsigned char b)
{
	static const unsigned char table[256] = {
		/* 0 */ 0, /* 1 */ 1, /* 2 */ 1, /* 3 */ 2,
		/* 4 */ 1, /* 5 */ 2, /* 6 */ 2, /* 7 */ 3,
		/* 8 */ 1, /* 9 */ 2, /* a */ 2, /* b */ 3,
		/* c */ 2, /* d */ 3, /* e */ 3, /* f */ 4,
		/* 10 */ 1, /* 11 */ 2, /* 12 */ 2, /* 13 */ 3,
		/* 14 */ 2, /* 15 */ 3, /* 16 */ 3, /* 17 */ 4,
		/* 18 */ 2, /* 19 */ 3, /* 1a */ 3, /* 1b */ 4,
		/* 1c */ 3, /* 1d */ 4, /* 1e */ 4, /* 1f */ 5,
		/* 20 */ 1, /* 21 */ 2, /* 22 */ 2, /* 23 */ 3,
		/* 24 */ 2, /* 25 */ 3, /* 26 */ 3, /* 27 */ 4,
		/* 28 */ 2, /* 29 */ 3, /* 2a */ 3, /* 2b */ 4,
		/* 2c */ 3, /* 2d */ 4, /* 2e */ 4, /* 2f */ 5,
		/* 30 */ 2, /* 31 */ 3, /* 32 */ 3, /* 33 */ 4,
		/* 34 */ 3, /* 35 */ 4, /* 36 */ 4, /* 37 */ 5,
		/* 38 */ 3, /* 39 */ 4, /* 3a */ 4, /* 3b */ 5,
		/* 3c */ 4, /* 3d */ 5, /* 3e */ 5, /* 3f */ 6,
		/* 40 */ 1, /* 41 */ 2, /* 42 */ 2, /* 43 */ 3,
		/* 44 */ 2, /* 45 */ 3, /* 46 */ 3, /* 47 */ 4,
		/* 48 */ 2, /* 49 */ 3, /* 4a */ 3, /* 4b */ 4,
		/* 4c */ 3, /* 4d */ 4, /* 4e */ 4, /* 4f */ 5,
		/* 50 */ 2, /* 51 */ 3, /* 52 */ 3, /* 53 */ 4,
		/* 54 */ 3, /* 55 */ 4, /* 56 */ 4, /* 57 */ 5,
		/* 58 */ 3, /* 59 */ 4, /* 5a */ 4, /* 5b */ 5,
		/* 5c */ 4, /* 5d */ 5, /* 5e */ 5, /* 5f */ 6,
		/* 60 */ 2, /* 61 */ 3, /* 62 */ 3, /* 63 */ 4,
		/* 64 */ 3, /* 65 */ 4, /* 66 */ 4, /* 67 */ 5,
		/* 68 */ 3, /* 69 */ 4, /* 6a */ 4, /* 6b */ 5,
		/* 6c */ 4, /* 6d */ 5, /* 6e */ 5, /* 6f */ 6,
		/* 70 */ 3, /* 71 */ 4, /* 72 */ 4, /* 73 */ 5,
		/* 74 */ 4, /* 75 */ 5, /* 76 */ 5, /* 77 */ 6,
		/* 78 */ 4, /* 79 */ 5, /* 7a */ 5, /* 7b */ 6,
		/* 7c */ 5, /* 7d */ 6, /* 7e */ 6, /* 7f */ 7,
		/* 80 */ 1, /* 81 */ 2, /* 82 */ 2, /* 83 */ 3,
		/* 84 */ 2, /* 85 */ 3, /* 86 */ 3, /* 87 */ 4,
		/* 88 */ 2, /* 89 */ 3, /* 8a */ 3, /* 8b */ 4,
		/* 8c */ 3, /* 8d */ 4, /* 8e */ 4, /* 8f */ 5,
		/* 90 */ 2, /* 91 */ 3, /* 92 */ 3, /* 93 */ 4,
		/* 94 */ 3, /* 95 */ 4, /* 96 */ 4, /* 97 */ 5,
		/* 98 */ 3, /* 99 */ 4, /* 9a */ 4, /* 9b */ 5,
		/* 9c */ 4, /* 9d */ 5, /* 9e */ 5, /* 9f */ 6,
		/* a0 */ 2, /* a1 */ 3, /* a2 */ 3, /* a3 */ 4,
		/* a4 */ 3, /* a5 */ 4, /* a6 */ 4, /* a7 */ 5,
		/* a8 */ 3, /* a9 */ 4, /* aa */ 4, /* ab */ 5,
		/* ac */ 4, /* ad */ 5, /* ae */ 5, /* af */ 6,
		/* b0 */ 3, /* b1 */ 4, /* b2 */ 4, /* b3 */ 5,
		/* b4 */ 4, /* b5 */ 5, /* b6 */ 5, /* b7 */ 6,
		/* b8 */ 4, /* b9 */ 5, /* ba */ 5, /* bb */ 6,
		/* bc */ 5, /* bd */ 6, /* be */ 6, /* bf */ 7,
		/* c0 */ 2, /* c1 */ 3, /* c2 */ 3, /* c3 */ 4,
		/* c4 */ 3, /* c5 */ 4, /* c6 */ 4, /* c7 */ 5,
		/* c8 */ 3, /* c9 */ 4, /* ca */ 4, /* cb */ 5,
		/* cc */ 4, /* cd */ 5, /* ce */ 5, /* cf */ 6,
		/* d0 */ 3, /* d1 */ 4, /* d2 */ 4, /* d3 */ 5,
		/* d4 */ 4, /* d5 */ 5, /* d6 */ 5, /* d7 */ 6,
		/* d8 */ 4, /* d9 */ 5, /* da */ 5, /* db */ 6,
		/* dc */ 5, /* dd */ 6, /* de */ 6, /* df */ 7,
		/* e0 */ 3, /* e1 */ 4, /* e2 */ 4, /* e3 */ 5,
		/* e4 */ 4, /* e5 */ 5, /* e6 */ 5, /* e7 */ 6,
		/* e8 */ 4, /* e9 */ 5, /* ea */ 5, /* eb */ 6,
		/* ec */ 5, /* ed */ 6, /* ee */ 6, /* ef */ 7,
		/* f0 */ 4, /* f1 */ 5, /* f2 */ 5, /* f3 */ 6,
		/* f4 */ 5, /* f5 */ 6, /* f6 */ 6, /* f7 */ 7,
		/* f8 */ 5, /* f9 */ 6, /* fa */ 6, /* fb */ 7,
		/* fc */ 6, /* fd */ 7, /* fe */ 7, /* ff */ 8};
	return table[b];
}

//Calculate the Hamming distance between two binary features
int StereoBinaryFeature::hammingDistance(const StereoBinaryFeature &sbf1, const StereoBinaryFeature &sbf2)
{
	if (sbf1.size_ == sbf2.size_)
	{
		//XOR
		int one_count = 0;
		for (int i = 0; i < sbf1.byte_; i++)
		{
			one_count += byteBitsLookUp(sbf1.feature_[i] ^ sbf2.feature_[i]);
		}
		return one_count;
	}
	else
	{
		cout << "Different size of binary feature\n";
		return -1;
	}
}

//Output the binary feature
void StereoBinaryFeature::writeFeatures(const vector<StereoBinaryFeature> &features, const string &path)
{
	ofstream bfout(path, ios::binary | ios::out);
	bfout.write((char *)&features[0].size_, sizeof(unsigned int));
	bfout.write((char *)&features[0].byte_, sizeof(unsigned int));
	size_t size = features.size();
	bfout.write((char *)&(size), sizeof(int));
	for (int i = 0; i < features.size(); i++)
	{
		for (int j = 0; j < features[0].byte_; j++)
		{
			bfout.write(&features[i].feature_[j], 1);
		}
	}
	bfout.flush();
	bfout.close();
}

//Input the binary feature
void StereoBinaryFeature::readFeatures(vector<StereoBinaryFeature> &features, const string &path)
{
	vector<StereoBinaryFeature>().swap(features);
	unsigned int byte_num;
	unsigned int bit_num;
	int size;
	ifstream bfin(path, ios::binary | ios::in);
	bfin.read((char *)&bit_num, sizeof(unsigned int));
	bfin.read((char *)&byte_num, sizeof(unsigned int));
	bfin.read((char *)&(size), sizeof(int));
	features.resize(size);
	for (int i = 0; i < features.size(); i++)
	{
		StereoBinaryFeature feature(bit_num);
		for (int j = 0; j < byte_num; j++)
		{
			bfin.read(&feature.feature_[j], 1);
		}
		features[i] = feature;
	}
	bfin.close();
}

} // namespace ghicp